const Spec = [

  [/^\s/, null],
  [/^\/\/.*/, null],
  [/^\/\*[\s\S]*?\*\//, null],


  [/^;/,';'],
  [/^{/,'{'],
  [/^}/,'}'],
  [/^\(/,'('],
  [/^\)/,')'],
  [/^,/,','],
  [/^\./,'.'],
  [/^\[/,'['],
  [/^\]/,']'],


  [/^\blet\b/, 'let'],
  [/^\bif\b/, 'if'],
  [/^\belse\b/, 'else'],
  [/^\btrue\b/, 'true'],
  [/^\bfalse\b/, 'false'],
  [/^\bnull\b/, 'null'],
  [/^\bwhile\b/, 'while'],
  [/^\bdo\b/, 'do'],
  [/^\bfor\b/, 'for'],
  [/^\bdef\b/, 'def'],
  [/^\breturn\b/, 'return'],
  [/^\bclass\b/, 'class'],
  [/^\bextends\b/, 'extends'],
  [/^\bsuper\b/, 'super'],
  [/^\bthis\b/, 'this'],
  [/^\bnew\b/, 'new'],
  [/^\bfunction\b/, 'function'],

  [/^\d+/, 'NUMBER'],
  [/^\w+/, 'IDENTIFIER'],
  // Equality operators: ==, !=
  [/^[=!]=/, 'EQUALITY_OPERATOR'],
  [/^&&/, 'LOGICAL_AND'],
  [/^\|\|/, 'LOGICAL_OR'],
  [/^!/, 'LOGICAL_NOT'],
  // Assignment operators: =, *=, /=, +=, -=
  [/^=/, 'SIMPLE_ASSIGN'],
  [/^[*/+-]=/, 'COMPLEX_ASSIGN'],
  [/^[><]=?/, 'RELATIONAL_OPERATOR'],
  [/^[+-]/, 'ADDITIVE_OPERATOR'],
  [/^[*\/]/, 'MULTIPLICATIVE_OPERATOR'],
  [/^"[^"]*"/, 'STRING'],
  [/^'[^']*'/, 'STRING'],
]

class Tokenizer{
  init(string){
    this._string = string;
    this._cursor = 0
    this.begin = 0;
    this.end = this._string.length
  }

  isEOF(){
    return this._cursor === this._string.length;
  }

  hasMoreTokens(){
    return this._cursor < this._string.length;
  }

  getNextToken(){
    if(!this.hasMoreTokens()){
      return null;
    }
    const string = this._string.slice(this._cursor);
    for(const [regexp,tokenType] of Spec){
      let begin = 0;
      begin += this._cursor
      const tokenValue = this._match(regexp,string);
      if(tokenValue ===null){
        continue;
      }
      if(tokenType === null){
        return this.getNextToken();
      }
      
      // this.begin += tokenValue.length +1
      return {
        type: tokenType,
        value:tokenValue,
        begin:begin,
        end:this._cursor
      };
    }
    
  }

  _match(regexp,string){
    const matched = regexp.exec(string);
    if(matched === null){
      return null;
    }
    
    this._cursor += matched[0].length;
    return matched[0]
  }
  getResult(){
    const result =[];
    let token = true
    while(token){
      token = this.getNextToken()
      result.push(token)
    }
    return result;
  }
}
// const tok = new Tokenizer();
// const str = `
// let bianl = '155';
// let num = 15;
// function asd(par){
//   return num;
// };
// `
// tok.init(str)
// console.log(tok.getResult());
export {Tokenizer}


// [
//   { type: 'let', value: 'let' },
//   { type: 'IDENTIFIER', value: 'bianl' },
//   { type: 'SIMPLE_ASSIGN', value: '=' },
//   { type: 'STRING', value: "'155'" },
//   { type: ';', value: ';' },
//   { type: 'let', value: 'let' },
//   { type: 'IDENTIFIER', value: 'num' },
//   { type: 'SIMPLE_ASSIGN', value: '=' },
//   { type: 'NUMBER', value: '15' },
//   { type: ';', value: ';' },
//   { type: 'function', value: 'function' },
//   { type: 'IDENTIFIER', value: 'asd' },
//   { type: '(', value: '(' },
//   { type: 'IDENTIFIER', value: 'par' },
//   { type: ')', value: ')' },
//   { type: '{', value: '{' },
//   { type: 'return', value: 'return' },
//   { type: 'IDENTIFIER', value: 'num' },
//   { type: ';', value: ';' },
//   { type: '}', value: '}' },
//   { type: ';', value: ';' },
//   null
// ]